package com.dji.activationDemo.websocket;

import android.os.Handler;

import com.dji.activationDemo.Constant;
import com.dji.activationDemo.uitls.WriteLog;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFactory;
import com.neovisionaries.ws.client.WebSocketFrame;
import com.neovisionaries.ws.client.WebSocketListener;

import java.io.IOException;
import java.util.List;
import java.util.Map;

public class WsImageManager {
    private static WsImageManager mImageInstance;

    private static final int FRAME_QUEUE_SIZE = 5;
    private static final int CONNECT_TIMEOUT = 5000;
    private static final String DEF_URL = Constant.DEF_URL+"Image";

    private String url;

    private WsImageStatus mStatus;
    public static WebSocket ws;
    private WsListener mListener;
    private long heartTime = System.currentTimeMillis();

    private boolean onOff = true;
    private Thread timeOut;
    private boolean start = true;

    private WsImageManager() {
    }

    public static WsImageManager getInstance() {
        if (mImageInstance == null) {
            synchronized (WsImageManager.class) {
                if (mImageInstance == null) {
                    mImageInstance = new WsImageManager();
                }
            }
        }
        return mImageInstance;
    }


    public void init() {
        System.out.println("start image init:");
        onOff = true;
        try {
            /**
             * configUrl其实是缓存在本地的连接地址
             * 这个缓存本地连接地址是app启动的时候通过http请求去服务端获取的,
             * 每次app启动的时候会拿当前时间与缓存时间比较,超过6小时就再次去服务端获取新的连接地址更新本地缓存
             */
            String configUrl = "";
            ws = new WebSocketFactory().createSocket(DEF_URL, CONNECT_TIMEOUT)
                    .setFrameQueueSize(FRAME_QUEUE_SIZE)//设置帧队列最大值为5
                    .setMissingCloseFrameAllowed(false)//设置不允许服务端关闭连接却未发送关闭帧
                    .addListener((WebSocketListener) (mListener = new WsListener()))//添加回调监听
                    .connectAsynchronously();//异步连接
            setStatus(WsImageStatus.CONNECTING);
            Constant.imageWebSocketState = "正在连接";
            WriteLog.writeLog("连接一次webSocket");
            System.out.println("连接一次webSocket");
        } catch (Exception e) {
            //e.printStackTrace();

            System.out.println("image init:");

        }
    }

    /**
     * 继承默认的监听空实现WebSocketAdapter,重写我们需要的方法
     * onTextMessage 收到文字信息
     * onConnected 连接成功
     * onConnectError 连接失败
     * onDisconnected 连接关闭
     */
    class WsListener extends WebSocketAdapter {


        @Override
        public void onTextMessage(WebSocket websocket, String text) throws Exception {
            super.onTextMessage(websocket, text);
            heartTime = System.currentTimeMillis();
            System.out.println(text);
            if (text.equals("heart")) {
                WriteLog.writeLog("图片信道：收到一次心跳");
                System.out.println("图片信道：收到一次心跳");
                Constant.imageWebSocketState = "连接成功";
            }
        }


        @Override
        public void onConnected(WebSocket websocket, Map<String, List<String>> headers)
                throws Exception {
            super.onConnected(websocket, headers);
            WriteLog.writeLog("图片信道：连接成功");
            Constant.imageWebSocketState = "连接成功";
            setStatus(WsImageStatus.CONNECT_SUCCESS);
            heartTime = System.currentTimeMillis();
            cancelReconnect();//连接成功的时候取消重连,初始化连接次数
            mHandler.post(mHeartCheck);
            start = true;
            timeOut();
            timeOut.start();
        }


        @Override
        public void onConnectError(WebSocket websocket, WebSocketException exception)
                throws Exception {
            super.onConnectError(websocket, exception);
            System.out.println("reconnect" + onOff);
            WriteLog.writeLog("图片信道：连接错误");
            Constant.imageWebSocketState = "连接错误";
            setStatus(WsImageStatus.CONNECT_FAIL);
            start = false;
//            mHandler.removeCallbacks(mHeartCheck);
            reconnect();//连接错误的时候调用重连方法
        }


        @Override
        public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer)
                throws Exception {
            super.onDisconnected(websocket, serverCloseFrame, clientCloseFrame, closedByServer);
            System.out.println("reconnect" + onOff);

            WriteLog.writeLog("图片信道：断开连接");
            Constant.imageWebSocketState = "断开连接";
            setStatus(WsImageStatus.CONNECT_FAIL);
//            mHandler.removeCallbacks(mHeartCheck);
            start = false;
            if (onOff)
                reconnect();//连接断开的时候调用重连方法
        }
    }

    private void setStatus(WsImageStatus status) {
        this.mStatus = status;
    }

    private WsImageStatus getStatus() {
        return mStatus;
    }

    public void disconnect() {
        if (ws != null)
            onOff = false;
        ws.disconnect();
    }

    public enum WsImageStatus {
        CONNECT_SUCCESS,//连接成功
        CONNECT_FAIL,//连接失败
        CONNECTING;//正在连接
    }

    private Handler mHandler = new Handler();

    private int reconnectCount = 0;//重连次数
    private long minInterval = 3000;//重连最小时间间隔
    private long maxInterval = 60000;//重连最大时间间隔

    public void reconnect() {

        //这里其实应该还有个用户是否登录了的判断 因为当连接成功后我们需要发送用户信息到服务端进行校验
        //由于我们这里是个demo所以省略了
        if (ws != null &&
                !ws.isOpen() &&//当前连接断开了
                getStatus() != WsImageStatus.CONNECTING) {//不是正在重连状态

            reconnectCount++;
            setStatus(WsImageStatus.CONNECTING);
            Constant.imageWebSocketState = "正在连接";

            long reconnectTime = minInterval;
//            if (reconnectCount > 3) {
//                url = DEF_URL;
//                long temp = minInterval * (reconnectCount - 2);
//                reconnectTime = temp > maxInterval ? maxInterval : temp;
//            }
            WriteLog.writeLog("准备开始第" + reconnectCount + "次重连。");
            System.out.println("图片服务准备开始第" + reconnectCount + "次重连。");
            mHandler.postDelayed(mReconnectTask, reconnectTime);
        }
    }

    private Runnable mReconnectTask = new Runnable() {
        @Override
        public void run() {
            try {
                ws = new WebSocketFactory().createSocket(DEF_URL, CONNECT_TIMEOUT)
                        .setFrameQueueSize(FRAME_QUEUE_SIZE)//设置帧队列最大值为5
                        .setMissingCloseFrameAllowed(false)//设置不允许服务端关闭连接却未发送关闭帧
                        .addListener(mListener = new WsListener())//添加回调监听
                        .connectAsynchronously();//异步连接
                setStatus(WsImageStatus.CONNECTING);
                Constant.imageWebSocketState = "正在连接";
            } catch (Exception e) {
                //e.printStackTrace();
                System.out.println(e.getMessage());
            }
        }
    };

    private Runnable mHeartCheck = new Runnable() {
        @Override
        public void run() {
            if ((System.currentTimeMillis() - heartTime) > 12000) {
                Constant.imageWebSocketState = "连接断开";
                WriteLog.writeLog("长时间没有收到心跳");
                System.out.println("长时间没有收到心跳");
                getInstance().disconnect();
                getInstance().init();
            }
            mHandler.postDelayed(mHeartCheck, 1000);
        }
    };


    public void timeOut() {
        timeOut = new Thread(new Runnable() {
            @Override
            public void run() {
                while (start) {
                    try {
                        if ((System.currentTimeMillis() - heartTime) > 12000) {
                            Constant.imageWebSocketState = "连接断开";
                            WriteLog.writeLog("长时间没有收到心跳");
                            System.out.println("长时间没有收到心跳");
                            getInstance().disconnect();
                            getInstance().init();
                        }
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        });
    }


    private void cancelReconnect() {
        reconnectCount = 0;
        mHandler.removeCallbacks(mReconnectTask);
    }
}
